/*
 *  Copyright (c) 2022-2022 ForteScarlet <ForteScarlet@163.com>
 *
 *  本文件是 simply-robot (或称 simple-robot 3.x 、simbot 3.x ) 的一部分。
 *
 *  simply-robot 是自由软件：你可以再分发之和/或依照由自由软件基金会发布的 GNU 通用公共许可证修改之，无论是版本 3 许可证，还是（按你的决定）任何以后版都可以。
 *
 *  发布 simply-robot 是希望它能有用，但是并无保障;甚至连可销售和符合某个特定的目的都不保证。请参看 GNU 通用公共许可证，了解详情。
 *
 *  你应该随程序获得一份 GNU 通用公共许可证的复本。如果没有，请看:
 *  https://www.gnu.org/licenses
 *  https://www.gnu.org/licenses/gpl-3.0-standalone.html
 *  https://www.gnu.org/licenses/lgpl-3.0-standalone.html
 *
 */

package love.forte.simboot.core.binder

import love.forte.simboot.core.application.ParameterBinderBuilder
import love.forte.simboot.listener.ParameterBinderFactory
import love.forte.simbot.InternalSimbotApi
import love.forte.simbot.SimbotIllegalStateException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.reflect.KFunction

internal class ParameterBinderBuilderImpl : ParameterBinderBuilder {
    private val globalBinders = ConcurrentLinkedQueue<ParameterBinderFactory>()
    private val idBinders = ConcurrentHashMap<String, ParameterBinderFactory>()
    
    override fun binder(id: String?, binderFactory: ParameterBinderFactory) {
        if (id == null) {
            globalBinders.add(binderFactory)
        } else {
            idBinders.merge(id, binderFactory) { old, curr ->
                // id为A的binder已经存在.
                throw SimbotIllegalStateException("The binder factory with id [$id] already exists. old: $old, current: $curr")
            }
        }
    }
    
    override fun binder(
        id: String?,
        function: KFunction<*>,
        instanceGetter: (ParameterBinderFactory.Context) -> Any?,
    ): ParameterBinderFactory {
        val factory = function.toBinderFactory(instanceGetter)
        binder(id, factory)
        return factory
    }
    
    @OptIn(InternalSimbotApi::class)
    fun build(): BinderManager {
        return CoreBinderManager(globalBinderFactories = globalBinders.toList(), idBinderFactories = idBinders)
    }
    
}